<?php
namespace app\api\controller;

use think\Controller;
use app\index\model\WxWx;
use app\reply\model\WxReply;
use app\msgReply\model\WxMsgreply; //注意路径中的大小写
use app\msg\model\WxMsg;
use app\news\model\WxNews;
class Index extends Controller {
	private $my_wx;
	private $my_input; // 'my_'前缀是为了避免命名重复
	private $my_output; // 'my_'前缀是为了避免命名重复
	private $my_pc; // 加解密类的实例，在获取微信发送数据时，判断后，执行实例化
	public function __construct() {
		parent::__construct ();
		// $user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
		// $this->my_output['text'] = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];
		if (! $this->checkFrom ()) { // 判断来源
			echo '来源非法';
			exit ();
		}
	}
	/**
	 * 流程控制
	 * 基本流程设计：
	 * 1、验证来源（初检，构造函数里完成，对URL验证）
	 * 2、获取微信公众号设置
	 * 3、验证来源（密码验证）
	 * 3、解析微信发来的信息（除明文外涉及加密/解密，建议开启加密）
	 * 4、对获取信息分类处理
	 * 5、获取对应处理的数据
	 * 6、返回处理结果
	 * 7、记录处理结果
	 */
	public function index() {
		/*
		 * 获得指定微信信息,
		 * 如果未找到相关信息，则中断后续操作
		 */
		$this->getWx ();
		// 验证来源（密码验证，判断是否为微信官方发来的信息，与token相关）
		$this->valid ();
		$this->getInputContent (); // 获得微信传递的内容，赋值到$this->my_input
		if ($this->my_input) {
			// 开始分类处理
			if (strtolower ( $this->my_input ['MsgType'] ) == 'event') {
				if ($this->my_input ['Event'] == 'MASSSENDJOBFINISH') { // 微信群发的结果通知
					$this->writeMassResult (); // 记录;
					exit ();
				} elseif ($this->my_input ['Event'] == 'CLICK') { // 自定义菜单点击事件
					if (isset ( $this->my_input ['EventKey'] ) && ! empty ( $this->my_input ['EventKey'] )) {
						$this->wayFromEventKey ();
					}
				} elseif ($this->my_input ['Event'] == 'scancode_waitmsg') {
					/*
					 * Event=>scancode_waitmsg
					 * EventKey=> 自己定义的
					 * ScanCodeInfo=> 这是一个数组（或许也有可能不是数组，待验证）
					 */
					$this->wayFromAnyone ();
				} elseif($this->my_input['Event']=='subscribe'){
					$this->wayFromSubscribe();
				}else { // 其他类型暂不回复
					echo '';
					exit ();
				}
			} elseif ($this->my_input ['MsgType'] == 'text') {
				$this->wayFromText ();
			} elseif ($this->my_input ['MsgType'] == 'image') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			} elseif ($this->my_input ['MsgType'] == 'voice') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			} elseif ($this->my_input ['MsgType'] == 'video') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			} elseif ($this->my_input ['MsgType'] == 'shortvideo') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			} elseif ($this->my_input ['MsgType'] == 'location') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			} elseif ($this->my_input ['MsgType'] == 'link') {
				$this->wayFromAnyone (); // 待开发，暂时以默认方式处理
			}
			/*
			 * 分类处理完毕，下面获取回复信息
			 * 注意：有可能在分类处理过程中就终止了，而无需接下来的步骤
			 * 当然，建议除了特殊的消息类型（如用户点击输入框等）都给予用户相应的回复
			 */
			$r = $this->responseMsg (); // 转化为直接回复的字符串，此时尚未加密
			                            // 判断‘way_of_key’是加强安全性,这是本地可以设置的强制加密参数，防止第三方窃取消息
			if (! empty ( $r )) {
				if ((isset ( $_GET ['encrypt_type'] ) && $_GET ['encrypt_type'] == 'aes') || $this->my_wx ['way_of_key'] == 1) {
					$errCode = $this->my_pc->encryptMsg ( $r, $_GET ['timestamp'], $_GET ["nonce"], $encryptMsg );
					$r = $encryptMsg; // 获取加密字符串
				}
			}
			echo $r; // 最终的回复内容，此处为正常预料之内回复的值！
			$id = $this->writeInput (); // 将用户发送内容写入数据库
			$this->writeOutput ( $id ); // 将发送给用户的内容记录到数据库中
			exit ();
		} else {
			echo '';
			exit ();
		}
	}
	private function checkFrom() {
		if (isset ( $_GET ['wx'] )) {
			// 第一步，验证来源
			if ($_GET ['wx'] > 0) { // 对URL做一个基本判断
				return true; // 进入下一步
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	/**
	 * wayFromText
	 * 消息为文本时的分类操作
	 * <br>主体内容是获取回复内容
	 * <br>赋值给$this->my_output
	 */
	private function wayFromText() {
		if ($this->my_input) {
			$this->my_output = '';
		}
		$keyword = trim ( $this->my_input ['Content'] );
		
		if ((! empty ( $keyword ) || $keyword === 0) && isset ( $this->my_wx )) { // 判断，关键词消息
			$res = $this->findReplyByKeyword ( $keyword );
			if ($res ['errCode']) {
				$this->my_output = '';
			} else {
				$this->my_output = $res ['data'];
			}
		} else {
			$this->my_output = '';
		}
	}
	
	/**
	 * wayFromEventKey
	 * 消息是自定义菜单key值时的分类操作
	 */
	private function wayFromEventKey() {
		if ($this->my_input) {
			$this->my_output = '';
		}
		$keyword = trim ( $this->my_input ['EventKey'] );
		
		if ((! empty ( $keyword ) || $keyword === 0) && isset ( $this->my_wx )) { // 判断，关键词消息
		                                                                          // 查询回复内容
			$WxReply = new WxReply ();
			$where = [ 
					'keyword' => $keyword,
					'aid' => $this->my_wx ['id'],
					'is_ok' => 1,
					'type' => 1,
					'is_menu_key' => 1 
			];
			$r = $WxReply->where ( $where )->limit ( 1 )->find ();
			if (! empty ( $r )) {
				$r = $r->toArray ();
				$r = $this->transReplyContent ( $r );
				$this->my_output = $r;
			} else {
				$r ['msg_type'] = 'text';
				$r ['text'] = '资源已下架！';
				$this->my_output = $r;
			}
		} else { // 关键词为空，这是意外情况，可能性极小
			$this->my_output = '';
		}
	}
	
	/**
	 * wayFromSubscribe
	 * 关注公众号时的分类操作
	 */
	private function wayFromSubscribe() {
		if ($this->my_input) {
			$this->my_output = '';
		}
// 		$keyword = trim ( $this->my_input ['EventKey'] );
		
// 		if (isset ( $this->my_wx ) ){ // 判断，关键词消息
			// 查询回复内容
			$WxReply = new WxReply ();
			$where = [
					'aid' => $this->my_wx ['id'],
					'is_ok' => 1,
					'type' => 2
			];
			$r = $WxReply->where ( $where )->limit ( 1 )->find ();
			if (! empty ( $r )) {
				$r = $r->toArray ();
				$r = $this->transReplyContent ( $r );
				$this->my_output = $r;
			} else {
				$this->my_output = '';
			}
		//} else { // 关键词为空，这是意外情况，可能性极小
			//$this->my_output = '';
		//}
	}
	
	/**
	 * findReplyByKeyword
	 * 通过关键词检索出回复数据
	 *
	 * @param string $keyword
	 * @return number[]|string[]|mixed[]
	 */
	private function findReplyByKeyword($keyword = NULL) {
		$keyword = $keyword === NULL ? $this->my_input ['Content'] : $keyword;
		$WxReply = new WxReply ();
		$where = [ 
				'keyword' => $keyword,
				'aid' => $this->my_wx ['id'],
				'is_ok' => 1,
				'type' => 1,
// 				'is_menu_key' => [ 
// 						'exp',
// 						'in(0) or isnull(is_menu_key)' 
// 				] 
		];
		$r = $WxReply->where ( $where )->limit ( 1 )->find ();
		if (! empty ( $r )) {
			$r = $r->toArray ();
			$r = $this->transReplyContent ( $r );
			return [ 
					'errCode' => 0,
					'errMsg' => '获取信息成功',
					'data' => $r 
			];
		} else {
			// 寻找非全匹配关键词
			$res = $this->getReplyLikeMatch ( $keyword );
			if (empty ( $res )) {
				// 返回无匹配回复
				$res = $this->replyNoMatch ( $this->my_wx ['id'] );
				if (empty ( $res )) {
					$res = [ 
							'errCode' => 0,
							'errMsg' => '找不到任何自定义的回复，看来只能由程序员代劳了',
							'data' => '' 
					];
				} else {
					$res = [ 
							'errCode' => 0,
							'errMsg' => '获取无匹配回复成功',
							'data' => $res 
					];
				}
			} else {
				$res = array (
						'errCode' => 0,
						'errMsg' => '获取非完全匹配关键词回复成功',
						'data' => $res 
				);
			}
			
			return $res;
		}
	}
	
	/**
	 * transReplyContent
	 * 回复数据格式化
	 * <br>将非文本内容进行重新赋值，并返回新的数据
	 *
	 * @param array $r 数据库中的原始数据
	 * @return array 结果数组
	 */
	private function transReplyContent($r = NULL) {
		if (empty ( $r ) || $r ['msg_type'] == 'text') {
			// 下一步
		} elseif ($r ['msg_type'] == 'news') {
			if(is_array($r ['news'])){
				$newsIDs = $r ['news'];
			}else{
				$newsIDs = json_decode ( $r ['news'], t );
			}
			foreach ( $newsIDs as $k => $v ) {
				$news [] = $this->getOneNews ( $v );
			}
			$r ['news'] = $news;
		} elseif ($r ['msg_type'] == 'img') {
			$file = new \app\file\controller\Index ();
			$res = $file->getUp2WxFile ( $r ['img'] );
			
			if ($res ['errCode']) {
				$r ['msg_type'] = 'text';
				$r ['text'] = '';
			} else {
				$r ['media_id'] = $res ['data'] ['media_id'];
			}
		}
		return $r;
	}
	
	private function getOneNews($id){
		$News = new WxNews();
		return $News->get($id)->toArray();
	}
	/**
	 * getReplyLikeMatch
	 * 通过关键词模糊查找自动回复
	 *
	 * @param string $k
	 */
	public function getReplyLikeMatch($k = NULL) {
		// 一、分词
		// 二、关键词去重复
		// 三、循环查找
		// 四、返回结果
		
		// 分词
		$keywords = $this->cutWord ( $k ); // $keywords为数组
		                                   // 去重复
		$keywords = array_unique ( $keywords );
		
		rsort ( $keywords, SORT_STRING ); // 重排列，以便将匹配度高的关键词前置；
		$reply = array ();
		$WxReply = new WxReply ();
		// 查找
		foreach ( $keywords as $k => $v ) {
			$where = [ 
					'aid' => $this->my_wx ['id'],
					'keyword' => $v,
					'type' => 1,
					'is_ok' => 1,
					'is_like' => 1 
			]
			// 'is_menu_key'=>0, //扩大搜索范围，则此处不对是否为自定义菜单做限制
			;
			$res = $WxReply->where ( $where )->order ( 'level desc,create_time desc' )->limit ( 1 )->find ();
			if (! empty ( $res )) {
				$reply = $res->toArray (); // 一旦找到一个合适的，立即退出循环
				break;
			}
		}
		$reply = $this->transReplyContent ( $reply );
		// 返回结果
		return $reply;
	}
	
	/**
	 * cutWord
	 * 分词
	 * @param unknown $k
	 * @return array 分割后的关键词数组
	 */
	public function cutWord($k = NULL) {
		require_once APP_PATH . '../extend/cutWord/phpanalysis.class.php';
		
		$do_fork = true; // 岐义处理
		$do_unit = true; // 新词识别
		$do_multi = false; // 多元切分
		$do_prop = false; // 词性标注
		$pri_dict = true; // 是否预装载全部词条
		                  
		// PhpAnalysis::$loadInit = false; // 参考demo--初始化类
		
		$pa = new \PhpAnalysis ( 'utf-8', 'utf-8', $pri_dict );
		// 载入词典
		$pa->LoadDict ();
		
		// 执行分词
		$pa->SetSource ( $k );
		$pa->differMax = $do_multi;
		$pa->unitWord = $do_unit;
		$pa->StartAnalysis ( $do_fork );
		
		$okresult = $pa->GetFinallyResult ( ' ', $do_prop ); // 结果，用空格分割
		$okresult = trim ( $okresult );
		$okresult = explode ( ' ', $okresult );
		return $okresult;
	}
	/**
	 * writeInput
	 * 记录用户发送的消息
	 */
	private function writeInput() {
		$r = $this->transInputType2Table ();
		$data ['aid'] = $this->my_wx ['id'];
		$r = array_merge ( $r, $data );
		$WxMsg = new WxMsg ();
		$res = $WxMsg->allowField ( true )->save ( $r );
		return $WxMsg->id;
	}
	/**
	 * writeOutput
	 * 记录回复的消息
	 */
	private function writeOutput($id = 0) {
		if (empty ( $this->my_output )){
			return false;
		}
		$WxMsgreply = new WxMsgreply ();
		// 参数设置
		$this->my_output ['my_name'] = $this->my_input ['ToUserName'];
		$this->my_output ['user_name'] = $this->my_input ['FromUserName'];
		$this->my_output ['msg_id'] = $id;
		if (isset ( $this->my_output ['id'] )){
			unset ( $this->my_output ['id'] );
		}
		$res = $WxMsgreply->allowField ( true )->save ( $this->my_output );
		// 待开发
	}
	/**
	 * replyNoMatch
	 * 无匹配的自动回复
	 * @param number $aid 公众号id
	 * @return mixed[]
	 */
	public function replyNoMatch($aid = NULL) {
		if ($aid === NULL) {
			return [ 
					'error' => 2,
					'message' => '系统没有正确交互内部信息',
					'result' => [ 
							'msg_type' => 'text',
							'text' => '抱歉，系统开小差了，请稍后再试' 
					] 
			];
		}
		$WxReply = new WxReply ();
		$where = [ 
				'type' => 3,
				'aid' => $this->my_wx ['id'],
				'is_ok' => 1 
		];
		$res = $WxReply->where ( $where )->order ( 'level desc,create_time desc' )->limit ( 1 )->find();
		if (! empty ( $res )) {
			$res = $res->toArray ();
			if (count ( $res ) > 0) {
				$res = $this->transReplyContent ( $res );
			} else {
				$res = ''; // 测试中
			}
		}
		return $res;
	}
	/**
	 * transInputType2Table
	 * 参数赋值
	 * <br>将微信提供的参数转化为本地数据库需要的参数
	 *
	 * @return mixed[]
	 */
	private function transInputType2Table() {
		$r = [];
		$r ['my_name'] = $this->my_input ['ToUserName'];
		$r ['user_name'] = $this->my_input ['FromUserName'];
		$r ['create_time'] = $this->my_input ['CreateTime'];
		$r ['msg_type'] = $this->my_input ['MsgType'];
		$r ['msg_id'] = $this->my_input ['MsgId'];
		$r ['content'] = isset($this->my_input ['Content'])?$this->my_input ['Content']:'';
		$r ['media_id'] = isset ( $this->my_input ['MediaId'] ) ? $this->my_input ['MediaId'] : '';
		$r ['img_url'] = isset ( $this->my_input ['PicUrl'] ) ? $this->my_input ['PicUrl'] : '';
		$r ['format'] = isset ( $this->my_input ['Format'] ) ? $this->my_input ['Format'] : '';
		$r ['thumb_media_id'] = isset ( $this->my_input ['ThumbMediaId'] ) ? $this->my_input ['ThumbMediaId'] : '';
		$r ['location_x'] = isset ( $this->my_input ['Location_X'] ) ? $this->my_input ['Location_X'] : '';
		$r ['location_y'] = isset ( $this->my_input ['Location_Y'] ) ? $this->my_input ['Location_Y'] : '';
		$r ['scale'] = isset ( $this->my_input ['Scale'] ) ? $this->my_input ['Scale'] : '';
		$r ['label'] = isset ( $this->my_input ['Label'] ) ? $this->my_input ['Label'] : '';
		$r ['title'] = isset ( $this->my_input ['Title'] ) ? $this->my_input ['Title'] : '';
		$r ['description'] = isset ( $this->my_input ['Description'] ) ? $this->my_input ['Description'] : '';
		$r ['url'] = isset ( $this->my_input ['Url'] ) ? $this->my_input ['Url'] : '';
		if ($r ['msg_type'] == 'event') {
			$r ['event'] = isset ( $this->my_input ['Event'] ) ? $this->my_input ['Event'] : '';
			$r ['event_key'] = isset ( $this->my_input ['EventKey'] ) ? $this->my_input ['EventKey'] : '';
			$r ['ticket'] = isset ( $this->my_input ['Ticket'] ) ? $this->my_input ['Ticket'] : '';
			$r ['latitude'] = isset ( $this->my_input ['Latitude'] ) ? $this->my_input ['Latitude'] : '';
			$r ['longitude'] = isset ( $this->my_input ['Longitude'] ) ? $this->my_input ['Longitude'] : '';
			$r ['precision'] = isset ( $this->my_input ['Precision'] ) ? $this->my_input ['Precision'] : '';
		}
		if (empty ( $this->my_output )) {
			$r ['is_reply'] = 0;
		} else {
			$r ['is_reply'] = 1;
		}
		if ($r ['msg_type'] == 'image')
			$r ['msg_type'] = 'img';
		if (isset ( $this->my_output ['type'] ) && $this->my_output ['type'] == 1)
			$r ['is_keyword'] = 1;
		else
			$r ['is_keyword'] = 0;
		return $r;
	}
	/**
	 * wayFromAnyone
	 * 默认回复
	 * @access private
	 * @goal 对于未知类型和部分多媒体类型消息的默认回复，改善用户体验
	 * @param String $text
	 */
	private function wayFromAnyone($text = NULL) {
		$this->my_output ['msg_type'] = 'text';
		$text = $text === NULL ? '消息收到，谢谢！' : $text;
		$this->my_output ['text'] = $text;
	}
	/**
	 * getWx
	 * 获取本地保存的的公众号数据
	 * @goal 将公众号数据赋值给$this->my_wx
	 */
	private function getWx() {
		$aid = $_GET ['wx'];
		$WxWx = new WxWx ();
		$res = $WxWx->get ( $aid ); // 获取微信数据
		
		if (empty ( $res )) {
			echo '';
			exit ();
		}
		$this->my_wx = $res->toArray (); // 转换数据格式并赋值给类私有变量，供其他函数调用
	}
	/**
	 * getInputContent
	 * 获取微信官方发送的输入内容
	 * @goal 将解析后的内容赋值给$this->my_input
	 * 
	 */
	private function getInputContent() {
// 		$postStr = $GLOBALS ["HTTP_RAW_POST_DATA"];
		//替换为更强大的“方法”获取输入的数据，防止部分服务器中由于php.ini设置不能正常获取的情况
		$postStr = file_get_contents("php://input"); 
		
		if (empty ( $postStr )) {
			$this->my_input = NULL;
		} else {
			if (isset ( $_GET ['encrypt_type'] ) && ($_GET ['encrypt_type'] == 'aes')) { // 判断是否加密，若加密，则执行解密
				$timestamp = $_GET ["timestamp"];
				$nonce = $_GET ["nonce"];
				$msg_signature = $_GET ["msg_signature"];
				require_once APP_PATH . '../extend/wxKey/wxBizMsgCrypt.php';
				$this->my_pc = new \WXBizMsgCrypt ( $this->my_wx->token, $this->my_wx->encoding_aes_key, $this->my_wx->app_id );
				$errCode = $this->my_pc->decryptMsg ( $msg_signature, $timestamp, $nonce, $postStr, $decryptMsg );
				if ($errCode) {
					echo $errCode;
					exit ();
				}
				$postStr = $decryptMsg;
			}
			
			libxml_disable_entity_loader ( true );
			$postObj = simplexml_load_string ( $postStr, 'SimpleXMLElement', LIBXML_NOCDATA );
			$this->my_input = json_encode ( $postObj );
			$this->my_input = json_decode ( $this->my_input, 1 );
		}
	}
	/**
	 * valid
	 * 双向验证
	 * @goal 在微信公众号官方管理后台填入URL和Token时，验证连接。
	 */
	private function valid() {
		// 第一次在微信端填写URL和Token时会验证
		if (isset ( $_GET ["echostr"] ) && $_GET ['echostr']) {
			$echoStr = $_GET ["echostr"];
			// valid signature , option
			if ($this->checkSignature ()) {
				echo $echoStr;
				exit ();
			} else {
				echo '验证失败';
				exit ();
			}
		}
	}
	/**
	 * writeMassResult
	 * 记录群发结果
	 * 
	 */
	private function writeMassResult() {
		$this->load->database ();
		// 数据初始化
		$msgID = $this->my_input ['MsgID']; // 注意这里的ID字母均大写
		$r ['msg_status'] = $this->my_input ['Status'];
		$r ['total_count'] = $this->my_input ['TotalCount'];
		$r ['filter_count'] = $this->my_input ['FilterCount'];
		$r ['sent_count'] = $this->my_input ['SentCount'];
		$r ['error_count'] = $this->my_input ['ErrorCount'];
		$a = $this->db->list_fields ( 'wx_mass' );
		$a = array_flip ( $a );
		$r = array_intersect_key ( $r, $a );
		$this->db->where ( 'msg_id', $msgID )->update ( 'wx_mass', $r );
	}
	/**
	 * responseMsg
	 * 获取本地设置的自动回复数据
	 * @return string 可用于回复的xml格式字符串；尚未加密
	 */
	private function responseMsg() {
		if (empty ( $this->my_output ) || $this->my_input === NULL) {
			return '';
		} else {
			if ($this->my_output ['msg_type'] == 'text') {
				
				if ($this->my_output ['text']) {
					$msg = $this->getTextReplyMsg ();
				} else {
					$msg = '';
				}
			} elseif ($this->my_output ['msg_type'] == 'img') {
				$msg = $this->getImgReplyMsg ();
			} elseif ($this->my_output ['msg_type'] == 'voice') {
			} elseif ($this->my_output ['msg_type'] == 'video') {
			} elseif ($this->my_output ['msg_type'] == 'news') {
				$msg = $this->getNewsReplyMsg ();
			} elseif ($this->my_output ['msg_type'] == 6) {
			} else {
				$msg = $this->getDefaultReplyMsg ();
			}
			return $msg; // 不直接对$this->my_output赋值，是为了使后续步骤中有可能利用该值，而$msg是String形式，不便使用
		}
	}
	/**
	 * getTextReplyMsg
	 * 拼装文本类型的回复
	 * @return string 可回复的xml格式字符串；未加密
	 */
	private function getTextReplyMsg() {
		$textTpl = "<xml>
					<ToUserName><![CDATA[%s]]></ToUserName>
					<FromUserName><![CDATA[%s]]></FromUserName>
					<CreateTime>%s</CreateTime>
					<MsgType><![CDATA[%s]]></MsgType>
					<Content><![CDATA[%s]]></Content>
					<FuncFlag>0</FuncFlag>
					</xml>";
		$time = time ();
		
		$resultStr = sprintf ( $textTpl, $this->my_input ['FromUserName'], $this->my_input ['ToUserName'], $time, 'text', $this->my_output ['text'] );
		return $resultStr;
	}
	/**
	 * getImgReplyMsg
	 * 拼装图片类型的回复
	 * @return string 可回复的xml格式字符串；未加密
	 */
	private function getImgReplyMsg() {
		$textTpl = "<xml>
					<ToUserName><![CDATA[%s]]></ToUserName>
					<FromUserName><![CDATA[%s]]></FromUserName>
					<CreateTime>%s</CreateTime>
					<MsgType><![CDATA[%s]]></MsgType>
					<Image>
					<MediaId><![CDATA[%s]]></MediaId>
					</Image>
					</xml>";
		$time = time ();
		$resultStr = sprintf ( $textTpl, $this->my_input ['FromUserName'], $this->my_input ['ToUserName'], $time, 'image', $this->my_output ['media_id'] );
		return $resultStr;
	}
	/**
	 * getNewsReplyMsg
	 * 拼装图文类型的回复
	 * @return string 可回复的xml格式字符串；未加密
	 */
	private function getNewsReplyMsg() {
		$headerTpl = "<xml>
			<ToUserName><![CDATA[%s]]></ToUserName>
			<FromUserName><![CDATA[%s]]></FromUserName>
			<CreateTime>%s</CreateTime>
			<MsgType><![CDATA[news]]></MsgType>
			<ArticleCount>%s</ArticleCount>
			<Articles>";
		$bodyTpl = "<item>
			<Title><![CDATA[%s]]></Title>
			<Description><![CDATA[%s]]></Description>
			<PicUrl><![CDATA[%s]]></PicUrl>
			<Url><![CDATA[%s]]></Url>
			</item>"; // 此处的Url是微信客户端中，用户点击图文时跳转的页面，类似于本系统中在图文编辑过程中的“外链”
		$footerTpl = "</Articles></xml>";
		$this->my_output ['create_time'] = time ();
		$header = sprintf ( $headerTpl, $this->my_input ['FromUserName'], $this->my_input ['ToUserName'], $this->my_output ['create_time'], count ( $this->my_output ['news'] ) );
		$url= 'http://' . $_SERVER ['HTTP_HOST'] . "/e/extend/WXForEcms/public/view.php?type=news&id=";
		$body="";//一定要初始化！且初始化为空字符串
		foreach ( $this->my_output ['news'] as $k => $v ) {
			// if ($v[isOpenOutside]) {
			// $v['URL']=$v['outsideUrl'];
			// }else{
			// }
			
			$body .= sprintf ( $bodyTpl, $v ['title'], $v ['abstract'], 'http://' . $_SERVER ['HTTP_HOST'] . $v ['title_img'], $url . $v ['id']); 
		}
		$res = $header . $body . $footerTpl;
		return $res;
	}
	/**
	 * getDefaultReplyMsg
	 * 拼装文本类型的回复
	 * @param string $word 回复给用户的文字内容
	 * @return string 可回复的xml格式字符串；未加密
	 */
	private function getDefaultReplyMsg($word = '谢谢关注！') {
		$this->my_output ['text'] = $word;
		return $this->getTextReplyMsg ();
	}
	/**
	 * checkSignature
	 * 验证令牌
	 * @throws Exception 异常：未设置本地令牌常量
	 * @return boolean 验证结果，通过则返回真
	 */
	private function checkSignature() {
		// you must define TOKEN by yourself
		if (! isset ( $this->my_wx ['token'] )) {
			throw new Exception ( 'TOKEN is not defined!' );
		}
		
		$signature = $_GET ["signature"];
		$timestamp = $_GET ["timestamp"];
		$nonce = $_GET ["nonce"];
		$token = $this->my_wx ['token'];
		$tmpArr = array (
				$token,
				$timestamp,
				$nonce 
		);
		// use SORT_STRING rule
		sort ( $tmpArr, SORT_STRING );
		$tmpStr = implode ( $tmpArr );
		$tmpStr = sha1 ( $tmpStr );
		if ($tmpStr == $signature) {
			return true;
		} else {
			return false;
		}
	}
}
